/**
 * can_lib.c
 * 
 * CAN通信库实现文件
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <net/if.h>
#include <linux/can.h>
#include <linux/can/raw.h>
#include "can_lib.h"

/**
 * 初始化CAN接口
 */
int can_init(const char *interface, uint32_t baud_rate)
{
    int s; // 套接字文件描述符
    struct sockaddr_can addr;
    struct ifreq ifr;

    // 创建套接字
    if ((s = socket(PF_CAN, SOCK_RAW, CAN_RAW)) < 0) {
        perror("Error creating socket");
        return CAN_ERROR_OPEN;
    }

    // 设置接口名称
    strcpy(ifr.ifr_name, interface);
    if (ioctl(s, SIOCGIFINDEX, &ifr) < 0) {
        perror("Error getting interface index");
        close(s);
        return CAN_ERROR_SETUP;
    }

    // 绑定CAN套接字到接口
    memset(&addr, 0, sizeof(addr));
    addr.can_family = AF_CAN;
    addr.can_ifindex = ifr.ifr_ifindex;
    
    if (bind(s, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
        perror("Error binding socket");
        close(s);
        return CAN_ERROR_SETUP;
    }

    return s;
}

/**
 * 发送CAN消息
 */
int can_send(int can_fd, const can_message_t *msg)
{
    struct can_frame frame;
    int nbytes;

    if (can_fd < 0 || msg == NULL) {
        return CAN_ERROR_SEND;
    }

    // 设置CAN帧ID
    if (msg->is_extended) {
        frame.can_id = msg->id | CAN_EFF_FLAG;
    } else {
        frame.can_id = msg->id;
    }

    // 设置远程帧标志
    if (msg->is_remote) {
        frame.can_id |= CAN_RTR_FLAG;
    }

    // 设置数据长度
    frame.can_dlc = msg->data_len;
    if (frame.can_dlc > 8) {
        frame.can_dlc = 8;
    }

    // 复制数据
    memcpy(frame.data, msg->data, frame.can_dlc);

    // 发送CAN帧
    nbytes = write(can_fd, &frame, sizeof(struct can_frame));
    if (nbytes < 0) {
        perror("Error sending CAN frame");
        return CAN_ERROR_SEND;
    }

    if (nbytes != sizeof(struct can_frame)) {
        fprintf(stderr, "Error: Incomplete CAN frame sent\n");
        return CAN_ERROR_SEND;
    }

    return CAN_SUCCESS;
}

/**
 * 接收CAN消息
 */
int can_receive(int can_fd, can_message_t *msg, int timeout_ms)
{
    struct can_frame frame;
    int nbytes;

    if (can_fd < 0 || msg == NULL) {
        return CAN_ERROR_RECEIVE;
    }

    // 设置超时
    if (timeout_ms != 0) {
        struct timeval timeout;
        fd_set readfds;

        FD_ZERO(&readfds);
        FD_SET(can_fd, &readfds);

        if (timeout_ms > 0) {
            timeout.tv_sec = timeout_ms / 1000;
            timeout.tv_usec = (timeout_ms % 1000) * 1000;
        } else {
            // 无限等待
            timeout.tv_sec = 0;
            timeout.tv_usec = 0;
        }

        int ret = select(can_fd + 1, &readfds, NULL, NULL, 
                         (timeout_ms > 0) ? &timeout : NULL);
        
        if (ret < 0) {
            perror("Error in select");
            return CAN_ERROR_RECEIVE;
        } else if (ret == 0) {
            // 超时
            return CAN_ERROR_RECEIVE;
        }
    }

    // 读取CAN帧
    nbytes = read(can_fd, &frame, sizeof(struct can_frame));
    if (nbytes < 0) {
        perror("Error reading CAN frame");
        return CAN_ERROR_RECEIVE;
    }

    if (nbytes != sizeof(struct can_frame)) {
        fprintf(stderr, "Error: Incomplete CAN frame received\n");
        return CAN_ERROR_RECEIVE;
    }

    // 解析CAN帧
    msg->is_extended = (frame.can_id & CAN_EFF_FLAG) ? 1 : 0;
    msg->is_remote = (frame.can_id & CAN_RTR_FLAG) ? 1 : 0;
    
    if (msg->is_extended) {
        msg->id = frame.can_id & CAN_EFF_MASK;
    } else {
        msg->id = frame.can_id & CAN_SFF_MASK;
    }

    msg->data_len = frame.can_dlc;
    memcpy(msg->data, frame.data, frame.can_dlc);

    return CAN_SUCCESS;
}

/**
 * 关闭CAN接口
 */
int can_close(int can_fd)
{
    if (can_fd < 0) {
        return CAN_ERROR_CLOSE;
    }

    if (close(can_fd) < 0) {
        perror("Error closing CAN socket");
        return CAN_ERROR_CLOSE;
    }

    return CAN_SUCCESS;
}

/**
 * 获取CAN错误信息
 */
const char *can_get_error_string(int error_code)
{
    switch (error_code) {
        case CAN_SUCCESS:
            return "Success";
        case CAN_ERROR_OPEN:
            return "Failed to open CAN interface";
        case CAN_ERROR_SETUP:
            return "Failed to setup CAN interface";
        case CAN_ERROR_SEND:
            return "Failed to send CAN message";
        case CAN_ERROR_RECEIVE:
            return "Failed to receive CAN message";
        case CAN_ERROR_CLOSE:
            return "Failed to close CAN interface";
        default:
            return "Unknown error";
    }
}